import 'dart:async';
import 'dart:convert';

import 'package:bloc/bloc.dart';
import 'package:dio/dio.dart';
import 'package:equatable/equatable.dart';
import 'package:formz/formz.dart';
import 'package:incidentmanager/models/case_address.dart';
import 'package:incidentmanager/models/case_along.dart';
import 'package:incidentmanager/models/case_content.dart';
import 'package:incidentmanager/models/case_type.dart';
import 'package:incidentmanager/models/post.dart';
import 'package:meta/meta.dart';

part 'case_event.dart';
part 'case_state.dart';

class CaseBloc extends Bloc<CaseEvent, CaseState> {
  final Dio httpClient;

  CaseBloc({@required this.httpClient}) : super(CaseInitial());

  @override
  Stream<Transition<CaseEvent, CaseState>> transformEvents(
    Stream<CaseEvent> events,
    TransitionFunction<CaseEvent, CaseState> transitionFn,
  ) {
    return super.transformEvents(
      events,
      transitionFn,
    );
  }

  @override
  Stream<CaseState> mapEventToState(CaseEvent event) async* {
    final currentState = state;
    if (event is CaseFetched && !_hasReachedMax(currentState)) {
      yield* _mapCaseListToState(currentState);
    }
  }

  /// 加载案例数据
  Stream<CaseState> _mapCaseListToState(CaseState currentState) async* {
    try {
      if (currentState is CaseInitial) {
        yield* _mapCaseInitialToState();
      } else if (currentState is CaseSuccess) {
        yield* _mapCaseLoadingToState(currentState);
      }
    } catch (_) {
      yield CaseFailure();
    }
  }

  /// 加载更多案例
  Stream<CaseState> _mapCaseLoadingToState(CaseSuccess currentState) async* {
    final posts = await _fetchPosts(currentState.posts.length, 20);
    yield posts.isEmpty
        ? currentState.copyWith(hasReachedMax: true)
        : CaseSuccess(
            posts: currentState.posts + posts,
            hasReachedMax: false,
          );
  }

  // 案例列表初始化
  Stream<CaseState> _mapCaseInitialToState() async* {
    final posts = await _fetchPosts(0, 20);
    yield CaseSuccess(posts: posts, hasReachedMax: false);
  }

  bool _hasReachedMax(CaseState state) =>
      state is CaseSuccess && state.hasReachedMax;

  /// 请求数据
  Future<List<Post>> _fetchPosts(int startIndex, int limit) async {
    final response = await httpClient.get(
        'https://jsonplaceholder.typicode.com/posts?_start=$startIndex&_limit=$limit');
    if (response.statusCode == 200) {
      final data = json.decode(response.data) as List;
      return data.map((rawPost) {
        return Post(
          id: rawPost['id'],
          title: rawPost['title'],
          body: rawPost['body'],
        );
      }).toList();
    } else {
      throw Exception('error fetching posts');
    }
  }
}
